inspector: Show size groups
authorMatthias Clasen <mclasen@redhat.com>
Wed, 21 May 2014 01:44:48 +0000 (21:44 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 21 May 2014 01:44:48 +0000 (21:44 -0400)
Add a tab that shows size groups of a widget. The properties
of the size group are available here, as well as the widgets
that are part of the size group. We highlight the widgets in
the application when their row in the inspector is hovered.

gtk/inspector/Makefile.am
gtk/inspector/init.c
gtk/inspector/size-groups.c [new file with mode: 0644]
gtk/inspector/size-groups.h [new file with mode: 0644]
gtk/inspector/window.c
gtk/inspector/window.ui

index 3a604233c8a849245f304ae1b0696be708702a90..faa567084234a7dfddfb0f5091d4e2000ac10301 100644 (file)
@@ -46,6 +46,8 @@ libgtkinspector_la_SOURCES =          \
        resources.c                     \
        signals-list.h                  \
        signals-list.c                  \
+       size-groups.h                   \
+       size-groups.c                   \
        visual.h                        \
        visual.c                        \
        widget-tree.h                   \
index a82b6f275921fcb186c426f0e55525e7010a4cf7..35b63f84626ebae082436f58fbf28480eb128d3c 100644 (file)
@@ -35,6 +35,7 @@
 #include "resource-list.h"
 #include "resources.h"
 #include "signals-list.h"
+#include "size-groups.h"
 #include "visual.h"
 #include "widget-tree.h"
 #include "window.h"
@@ -59,6 +60,7 @@ gtk_inspector_init (void)
   g_type_ensure (GTK_TYPE_INSPECTOR_PYTHON_SHELL);
   g_type_ensure (GTK_TYPE_INSPECTOR_RESOURCE_LIST);
   g_type_ensure (GTK_TYPE_INSPECTOR_SIGNALS_LIST);
+  g_type_ensure (GTK_TYPE_INSPECTOR_SIZE_GROUPS);
   g_type_ensure (GTK_TYPE_INSPECTOR_VISUAL);
   g_type_ensure (GTK_TYPE_INSPECTOR_WIDGET_TREE);
   g_type_ensure (GTK_TYPE_INSPECTOR_WINDOW);
diff --git a/gtk/inspector/size-groups.c b/gtk/inspector/size-groups.c
new file mode 100644 (file)
index 0000000..d4b27d1
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include "size-groups.h"
+#include "window.h"
+#include "gtkwidgetprivate.h"
+
+
+typedef struct {
+  GtkListBoxRow parent;
+  GtkWidget *widget;
+} SizeGroupRow;
+
+typedef struct {
+  GtkListBoxRowClass parent;
+} SizeGroupRowClass;
+
+enum {
+  PROP_WIDGET = 1,
+  LAST_PROPERTY
+};
+
+GParamSpec *properties[LAST_PROPERTY] = { NULL };
+
+G_DEFINE_TYPE (SizeGroupRow, size_group_row, GTK_TYPE_LIST_BOX_ROW)
+
+static void
+size_group_row_init (SizeGroupRow *row)
+{
+}
+
+static void
+size_group_row_get_property (GObject    *object,
+                             guint       property_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  SizeGroupRow *row = (SizeGroupRow*)object;
+
+  switch (property_id)
+    {
+    case PROP_WIDGET:
+      g_value_set_pointer (value, row->widget);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+size_group_row_set_property (GObject      *object,
+                             guint         property_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  SizeGroupRow *row = (SizeGroupRow*)object;
+
+  switch (property_id)
+    {
+    case PROP_WIDGET:
+      if (row->widget)
+        g_object_remove_weak_pointer (G_OBJECT (row->widget), (gpointer *)&row->widget);
+      row->widget = g_value_get_pointer (value);
+      if (row->widget)
+        g_object_add_weak_pointer (G_OBJECT (row->widget), (gpointer *)&row->widget);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+static void
+size_group_row_finalize (GObject *object)
+{
+  SizeGroupRow *row = (SizeGroupRow *)object;
+
+  if (row->widget)
+    g_object_remove_weak_pointer (G_OBJECT (row->widget), (gpointer *)&row->widget);
+
+  G_OBJECT_CLASS (size_group_row_parent_class)->finalize (object);
+}
+
+static void
+size_group_state_flags_changed (GtkWidget     *widget,
+                                GtkStateFlags  old_state)
+{
+  SizeGroupRow *row = (SizeGroupRow*)widget;
+  GtkStateFlags state;
+
+  if (!row->widget)
+    return;
+
+  state = gtk_widget_get_state_flags (widget);
+  if ((state & GTK_STATE_FLAG_PRELIGHT) != (old_state & GTK_STATE_FLAG_PRELIGHT))
+    {
+      if (state & GTK_STATE_FLAG_PRELIGHT)
+        gtk_inspector_start_highlight (row->widget);
+      else
+        gtk_inspector_stop_highlight (row->widget);
+    }
+}
+
+static void
+size_group_row_class_init (SizeGroupRowClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->finalize = size_group_row_finalize;
+  object_class->get_property = size_group_row_get_property;
+  object_class->set_property = size_group_row_set_property;
+
+  widget_class->state_flags_changed = size_group_state_flags_changed;
+
+  properties[PROP_WIDGET] =
+    g_param_spec_pointer ("widget", "Widget", "Widget", G_PARAM_READWRITE);
+
+  g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
+
+}
+
+G_DEFINE_TYPE (GtkInspectorSizeGroups, gtk_inspector_size_groups, GTK_TYPE_BOX)
+
+static void
+clear_view (GtkInspectorSizeGroups *sl)
+{
+  GList *children, *l;
+  GtkWidget *child;
+
+  children = gtk_container_get_children (GTK_CONTAINER (sl));
+  for (l = children; l; l = l->next)
+    {
+      child = l->data;
+      gtk_container_remove (GTK_CONTAINER (sl), child);
+    }
+  g_list_free (children);
+}
+
+static void
+add_widget (GtkInspectorSizeGroups *sl,
+            GtkListBox             *listbox,
+            GtkWidget              *widget)
+{
+  GtkWidget *row;
+  GtkWidget *label;
+  gchar *text;
+
+  row = g_object_new (size_group_row_get_type (), "widget", widget, NULL);
+  text = g_strdup_printf ("%p (%s)", widget, g_type_name_from_instance ((GTypeInstance*)widget));
+  label = gtk_label_new (text);
+  g_free (text);
+  g_object_set (label, "margin", 10, NULL);
+  gtk_widget_set_halign (label, GTK_ALIGN_START);
+  gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
+  gtk_widget_show (label);
+  gtk_container_add (GTK_CONTAINER (row), label);
+  gtk_container_add (GTK_CONTAINER (listbox), row);
+}
+
+static void
+add_size_group (GtkInspectorSizeGroups *sl,
+                GtkSizeGroup           *group)
+{
+  GtkWidget *frame, *box, *box2;
+  GtkWidget *label, *sw, *combo;
+  GSList *widgets, *l;
+  GtkWidget *listbox;
+
+  frame = gtk_frame_new (NULL);
+  gtk_container_add (GTK_CONTAINER (sl), frame);
+  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_container_add (GTK_CONTAINER (frame), box);
+
+  box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+  gtk_container_add (GTK_CONTAINER (box), box2);
+
+  label = gtk_label_new (_("Ignore hidden"));
+  g_object_set (label, "margin", 10, NULL);
+  gtk_widget_set_halign (label, GTK_ALIGN_START);
+  gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
+  gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
+
+  sw = gtk_switch_new ();
+  g_object_set (sw, "margin", 10, NULL);
+  gtk_widget_set_halign (sw, GTK_ALIGN_END);
+  gtk_widget_set_valign (sw, GTK_ALIGN_BASELINE);
+  g_object_bind_property (group, "ignore-hidden",
+                          sw, "active",
+                          G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+  gtk_box_pack_start (GTK_BOX (box2), sw, FALSE, FALSE, 0);
+
+  box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
+  gtk_container_add (GTK_CONTAINER (box), box2);
+
+  label = gtk_label_new (_("Mode"));
+  g_object_set (label, "margin", 10, NULL);
+  gtk_widget_set_halign (label, GTK_ALIGN_START);
+  gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
+  gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
+
+  combo = gtk_combo_box_text_new ();
+  g_object_set (combo, "margin", 10, NULL);
+  gtk_widget_set_halign (combo, GTK_ALIGN_END);
+  gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("None"));
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Horizontal"));
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Vertical"));
+  gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), _("Both"));
+  g_object_bind_property (group, "mode",
+                          combo, "active",
+                          G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
+  gtk_box_pack_start (GTK_BOX (box2), combo, FALSE, FALSE, 0);
+
+  listbox = gtk_list_box_new ();
+  gtk_container_add (GTK_CONTAINER (box), listbox);
+  gtk_list_box_set_selection_mode (GTK_LIST_BOX (listbox), GTK_SELECTION_NONE);
+
+  widgets = gtk_size_group_get_widgets (group);
+  for (l = widgets; l; l = l->next)
+    add_widget (sl, GTK_LIST_BOX (listbox), GTK_WIDGET (l->data));
+
+  gtk_widget_show_all (frame);
+}
+
+void
+gtk_inspector_size_groups_set_object (GtkInspectorSizeGroups *sl,
+                                      GObject                *object)
+{
+  clear_view (sl);
+  gtk_widget_hide (GTK_WIDGET (sl));
+
+  if (GTK_IS_WIDGET (object))
+    {
+      GSList *groups, *l;
+
+      gtk_widget_show (GTK_WIDGET (sl));
+      groups = _gtk_widget_get_sizegroups (GTK_WIDGET (object));
+      for (l = groups; l; l = l->next)
+        {
+          GtkSizeGroup *group = l->data;
+          add_size_group (sl, group);
+        }
+    }
+}
+
+static void
+gtk_inspector_size_groups_init (GtkInspectorSizeGroups *sl)
+{
+  g_object_set (sl,
+                "orientation", GTK_ORIENTATION_VERTICAL,
+                "margin", 40,
+                "spacing", 20,
+                NULL);
+}
+
+static void
+gtk_inspector_size_groups_class_init (GtkInspectorSizeGroupsClass *klass)
+{
+}
+
+// vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/size-groups.h b/gtk/inspector/size-groups.h
new file mode 100644 (file)
index 0000000..2d4ccaa
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GTK_INSPECTOR_SIZE_GROUPS_H_
+#define _GTK_INSPECTOR_SIZE_GROUPS_H_
+
+#include <gtk/gtk.h>
+
+#define GTK_TYPE_INSPECTOR_SIZE_GROUPS            (gtk_inspector_size_groups_get_type())
+#define GTK_INSPECTOR_SIZE_GROUPS(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_SIZE_GROUPS, GtkInspectorSizeGroups))
+#define GTK_INSPECTOR_SIZE_GROUPS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_INSPECTOR_SIZE_GROUPS, GtkInspectorSizeGroupsClass))
+#define GTK_INSPECTOR_IS_SIZE_GROUPS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_INSPECTOR_SIZE_GROUPS))
+#define GTK_INSPECTOR_IS_SIZE_GROUPS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_INSPECTOR_SIZE_GROUPS))
+#define GTK_INSPECTOR_SIZE_GROUPS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_INSPECTOR_SIZE_GROUPS, GtkInspectorSizeGroupsClass))
+
+
+typedef struct _GtkInspectorSizeGroups
+{
+  GtkBox parent;
+} GtkInspectorSizeGroups;
+
+typedef struct _GtkInspectorSizeGroupsClass
+{
+  GtkBoxClass parent;
+} GtkInspectorSizeGroupsClass;
+
+G_BEGIN_DECLS
+
+GType gtk_inspector_size_groups_get_type   (void);
+void  gtk_inspector_size_groups_set_object (GtkInspectorSizeGroups *sl,
+                                            GObject                *object);
+
+G_END_DECLS
+
+#endif // _GTK_INSPECTOR_SIZE_GROUPS_H_
+
+// vim: set et sw=2 ts=2:
index 4d8b27f02ec0066a2bcd8f564bbc989f1e5c5519..25290ef472207409f14f16cfd4927c3248d7d636 100644 (file)
@@ -34,6 +34,7 @@
 #include "python-hooks.h"
 #include "python-shell.h"
 #include "button-path.h"
+#include "size-groups.h"
 #include "data-list.h"
 #include "signals-list.h"
 #include "actions.h"
@@ -70,6 +71,7 @@ on_widget_tree_selection_changed (GtkInspectorWidgetTree *wt,
   gtk_inspector_button_path_set_object (GTK_INSPECTOR_BUTTON_PATH (iw->button_path), selected);
   gtk_inspector_classes_list_set_object (GTK_INSPECTOR_CLASSES_LIST (iw->classes_list), selected);
   gtk_inspector_css_editor_set_object (GTK_INSPECTOR_CSS_EDITOR (iw->widget_css_editor), selected);
+  gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected);
   gtk_inspector_data_list_set_object (GTK_INSPECTOR_DATA_LIST (iw->data_list), selected);
   gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected);
   if (GTK_IS_WIDGET (selected))
@@ -168,6 +170,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_hierarchy);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, python_shell);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, widget_popup);
+  gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, data_list);
   gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, actions);
 
index 6b29a6d0cee9ac98a24a8e1fe429e4e01d0772ee..4ee58ec9a200cfa87bd2c1c1938f91fa3365ede7 100644 (file)
                         <property name="label" translatable="yes">Custom CSS</property>
                       </object>
                     </child> 
+                    <child>
+                      <object class="GtkInspectorSizeGroups" id="size_groups">
+                      </object>
+                      <packing>
+                        <property name="tab_expand">True</property>
+                        <property name="tab_fill">True</property>
+                      </packing>
+                    </child>
+                    <child type="tab">
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Sizegroups</property>
+                      </object>
+                    </child> 
                     <child>
                       <object class="GtkInspectorDataList" id="data_list">
                       </object>